﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace cURL4Net
{
    /// <summary>
    /// <see cref="http://curl.haxx.se/libcurl/c/allfuncs.html"/>
    /// </summary>
    public sealed class curl
    {
        static LibraryWrapper Wrapper = new LibraryWrapper("libcurl.dll");

        // for state management
        static cURLcode m_cURLcode = cURLcode.CURLE_FAILED_INIT;

        #region curl_global_init
        public delegate cURLcode curl_global_init(int flags);

        /// <summary>
        /// Process-wide initialization -- call only once per process. <see cref="http://curl.haxx.se/libcurl/c/curl_global_init.html"/>
        /// </summary>
        /// <param name="flags">An or'd combination of
        /// <see cref="cURLinitFlag"/> members.</param>
        /// <returns>A <see cref="CURLcode"/>, hopefully
        /// <c>CURLcode.CURLE_OK</c>.</returns>
        public static cURLcode global_init(CURLinitFlag flags)
        {
            var curl_global_init = Wrapper.Invoke<curl_global_init>("curl_global_init");

            m_cURLcode = curl_global_init((int)flags);
            return m_cURLcode;
        }


        #endregion

        #region curl_global_cleanup
        public delegate void curl_global_cleanup();

        /// <summary>
        /// Process-wide cleanup -- call just before exiting process. <see cref="http://curl.haxx.se/libcurl/c/curl_global_cleanup.html"/>
        /// </summary>
        /// <remarks>
        /// While it's not necessary that your program call this method
        /// before exiting, doing so will prevent leaks of native cURL resources.
        /// </remarks>
        public static void global_cleanup()
        {
            if (m_cURLcode == cURLcode.CURLE_OK)
            {
                var curl_global_cleanup = Wrapper.Invoke<curl_global_cleanup>("curl_global_cleanup");
                curl_global_cleanup();

                m_cURLcode = cURLcode.CURLE_FAILED_INIT;
            }
        } 
        #endregion

        #region curl_global_init_mem

        /// <summary>
        /// <see cref="http://curl.haxx.se/libcurl/c/curl_global_init_mem.html"/>
        /// </summary>
        /// <param name="flags"></param>
        /// <param name="curl_malloc_callback"></param>
        /// <param name="curl_free_callback"></param>
        /// <param name="curl_realloc_callback"></param>
        /// <param name="curl_strdup_callback"></param>
        /// <param name="curl_calloc_callback"></param>
        /// <returns></returns>
        public static cURLcode global_init_mem(CURLinitFlag flags,
            Action curl_malloc_callback,
            Action curl_free_callback,
            Action curl_realloc_callback,
            Action curl_strdup_callback,
            Action curl_calloc_callback)
        {
            throw new NotImplementedException();
            //       CURLcode curl_global_init_mem(long flags,
            //curl_malloc_callback m,
            //curl_free_callback f,
            //curl_realloc_callback r,
            //curl_strdup_callback s,
            //curl_calloc_callback c);
        }

        #endregion

        #region curl_escape

        /// <summary>
        /// URL encode a String. <see cref="http://curl.haxx.se/libcurl/c/curl_escape.html"/>
        /// </summary>
        /// <param name="url">The string to URL encode.</param>
        /// <param name="length">Input string length;
        /// use 0 for cURL to determine.</param>
        /// <returns>A new URL encoded string.</returns>
        /// <exception cref="System.InvalidOperationException">
        /// Thrown if cURL isn't properly initialized.</exception>
        [Obsolete("http://curl.haxx.se/libcurl/c/curl_easy_escape.html")]
        public static string escape(string url, int length)
        {
            var curl_escape = Wrapper.Invoke<Func<string, int, IntPtr>>("curl_escape");
            IntPtr p = curl_escape(url, length);
            String s = Marshal.PtrToStringAnsi(p);
            curl.free(p);
            return s;
        } 
        #endregion

        #region curl_unescape
        /// <summary>
        /// URL decode a String. <see cref="http://curl.haxx.se/libcurl/c/curl_unescape.html"/>
        /// </summary>
        /// <param name="url">The string to URL decode.</param>
        /// <param name="length">Input string length;
        /// use 0 for cURL to determine.</param>
        /// <returns>A new URL decoded string.</returns>
        /// <exception cref="System.InvalidOperationException">
        /// Thrown if cURL isn't properly initialized.</exception>
        public static string unescape(string url, int length)
        {
            var curl_unescape = Wrapper.Invoke<Func<string, int, IntPtr>>("curl_unescape");
            IntPtr p = curl_unescape(url, length);
            String s = Marshal.PtrToStringAnsi(p);
            curl.free(p);
            return s;
        } 
        #endregion

        #region curl_free
        public delegate void curl_free(IntPtr ptr);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ptr"></param>
        public static void free(IntPtr ptr)
        {
            var curl_free = Wrapper.Invoke<curl_free>("curl_free");
        } 
        #endregion

        #region curl_version
        public delegate IntPtr curl_version();
        /// <summary>
        /// Get the underlying cURL version as a string, example "7.12.2".
        /// </summary>
        /// <exception cref="System.InvalidOperationException">
        /// Thrown if cURL isn't properly initialized.</exception>
        public static string version()
        {

            var curl_version = Wrapper.Invoke<curl_version>("curl_version");
            return Marshal.PtrToStringAnsi(curl_version());

        } 
        #endregion

        #region curl_formadd

        #endregion

        #region curl_formfree
        
        #endregion

        #region curl_getdate
        
        #endregion

        #region curl_slist_append

        #endregion

        #region curl_slist_free_all
        
        #endregion

        #region curl_version_info
        
        #endregion

        #region easy
        curl_easy _easy;
        public curl_easy easy
        {
            get
            {
                if (this._easy == null)
                {
                    this._easy = new curl_easy();
                }

                return this._easy;
            }
        } 
        #endregion

        #region multi
        curl_multi _multi;
        public curl_multi multi
        {
            get
            {
                if (this._multi == null)
                {
                    this._multi = new curl_multi();
                }

                return this._multi;
            }
        } 
        #endregion

        #region share
        curl_share _share;
        public curl_share share
        {
            get
            {
                if (this._share == null)
                {
                    this._share = new curl_share();
                }

                return this._share;
            }
        } 
        #endregion
    }
}
